import type {
  DataTableBaseColumn, DataTableCreateRowClassName, DataTableCreateRowKey,
  DataTableCreateRowProps, DataTableCreateSummary, DataTableProps,
  PaginationProps, PopoverProps, ScrollbarProps, SpinProps, TagProps,
} from 'naive-ui'
import type { DataTableHeightForRow, DataTableSelectionOptions } from 'naive-ui/es/data-table/src/interface'
import type { Ref, VNodeChild } from 'vue'
import type { Expose as NvSearchInst } from './components/search/types'
import type { UseToolbarReturn } from './components/toolbar/use-toolbar'
import type { NvDrawerProps, NvModalProps } from './form/wrapper/types'
import type { NV_TABLE_COLUMN_KEYS } from './use-columns'
import type { NvFormInst, NvFormItemOption, NvFormMode, NvFormOption } from '@/form/types'
import type { Constructor, NvBtnOption, NvDict, RowData, Size } from '@/types'
import type { DictComponentSlotParams } from '@/utils/use-dict'

export interface NvCrudProps {
  'data': RowData[]
  'option': NvCrudOption
  'pagination'?: PaginationProps
  'onSearch'?: (done: () => void) => void
  'onRefresh'?: (done: () => void) => void
  'onImport'?: () => void
  'onExport'?: () => void
  'onRowDelete'?: (rowData: any) => void
  'onRowUpdate'?: (rowData: any, done: (close?: boolean) => void) => void
  'onRowSave'?: (rowData: any, done: (close?: boolean) => void) => void
  'onLoad'?: (rowData: any) => Promise<void>
  'onScroll'?: DataTableProps['onScroll']
  'onUpdate:filters'?: DataTableProps['onUpdate:filters']
  'onUpdate:page'?: DataTableProps['onUpdate:page']
  'onUpdate:pageSize'?: DataTableProps['onUpdate:pageSize']
  'onUpdate:sorter'?: DataTableProps['onUpdate:sorter']
}

export interface NvCrudEmits {
  (e: string, ...args: any[]): void
}

type BaseColumnKeys = Exclude<typeof NV_TABLE_COLUMN_KEYS[number], 'children'>
type BaseColumn = Pick<DataTableBaseColumn, BaseColumnKeys>

type ViewItemIgnoredProps = 'rule' | 'formVisible' | 'readonly' | 'disabled' | 'clearable' | 'placeholder' | 'defaultValue'
export type NvViewItemOption<T = RowData> = Omit<NvFormItemOption<T>, ViewItemIgnoredProps>

type SearchItemIgnoredProps = 'suffix' | 'formVisible'
export type NvSearchItemOption<T = RowData> = Omit<NvFormItemOption<T>, SearchItemIgnoredProps>

type NvCrudFieldRenderParams = DictComponentSlotParams
export interface NvCrudFieldOption<T = RowData> extends Omit<BaseColumn, 'render'>, NvFormItemOption<T> {
  title?: string | (() => VNodeChild)
  children?: Record<string, NvCrudFieldOption<T>>
  render?: (params: NvCrudFieldRenderParams) => VNodeChild

  cellDict?: NvDict<T>

  order?: number
  visible?: boolean | Ref<boolean>
  viewForm?: NvViewItemOption<T> | boolean
  addForm?: NvFormItemOption<T> | boolean
  editForm?: NvFormItemOption<T> | boolean
  search?: NvSearchItemOption<T> | boolean
}

export interface NvFormWrapper extends Omit<NvModalProps, 'title'>, Omit<NvDrawerProps, 'title'> {
  type?: 'modal' | 'drawer'
  title?: (mode: NvFormMode) => VNodeChild
}

interface NvBaseColumnOption {
  fixed?: 'left' | 'right'
  width?: number | string
  minWidth?: string | number
  maxWidth?: string | number
  className?: string
  align?: 'left' | 'center' | 'right'
  titleAlign?: 'left' | 'center' | 'right'
  resizable?: boolean
}

interface NvSelectionOption<T> extends NvBaseColumnOption {
  multiple?: boolean
  disabled?: (row: T) => boolean
  options?: DataTableSelectionOptions<T>
}

interface NvSerialNoOption<T> extends NvBaseColumnOption {
  title?: string | (() => VNodeChild)
  render?: (rowData: T, rowIndex: number) => VNodeChild
}

interface NvExpansionOption<T> extends NvBaseColumnOption {
  title?: string | (() => VNodeChild)
  expandable?: (row: T) => boolean
  renderExpand: (row: T, index: number) => VNodeChild
}

interface NvMultiSelectBarOption {
  renderTip?: (checkedCount: number) => VNodeChild
  type?: TagProps['type']
  bordered?: boolean
  round?: boolean
}

interface NvRowActionsOption extends NvBaseColumnOption {
  title?: string | (() => VNodeChild)
  viewBtn?: NvBtnOption | boolean | Ref<boolean>
  editBtn?: NvBtnOption | boolean | Ref<boolean>
  delBtn?: NvBtnOption | boolean | Ref<boolean>
}

export interface NvActionbarOption {
  addBtn?: NvBtnOption | boolean | Ref<boolean>
}

interface ToolbarRenderParams extends UseToolbarReturn {
  loading: Ref<boolean>
  size: Ref<Size>
  showTooltips: Ref<boolean>
}
export interface NvToolbarOption {
  showTooltips?: boolean | Ref<boolean>
  render?: (params: ToolbarRenderParams) => (Constructor | (() => VNodeChild))[]
}

interface NvCollapseBtnOption extends Omit<NvBtnOption, 'content'> {
  content?: boolean | ((collapsed: boolean) => VNodeChild)
}

export interface NvSearchActions {
  span?: number | string
  searchBtn?: NvBtnOption | boolean | Ref<boolean>
  clearBtn?: NvBtnOption | boolean | Ref<boolean>
  collapseBtn?: NvCollapseBtnOption | boolean | Ref<boolean>
  teleportTo?: string
}

export interface NvSearchFormOption {
  showLabel?: boolean
  labelWidth?: number | string
  labelAlign?: 'left' | 'center' | 'right'
  labelPlacement?: 'top' | 'left'

  collapsedRow?: number
  collapsedNum?: number

  actions?: NvSearchActions | boolean
}

export interface NvTargetStorage {
  getItem: (key: string) => string | null | Promise<string | null>
  setItem: (key: string, value: string) => void
  removeItem: (key: string) => void
}

export interface NvCrudOption<T = any> extends Omit<NvFormOption<T>, 'fields'> {
  paginateSinglePage?: boolean
  minHeight?: string | number
  maxHeight?: string | number
  rowClassName?: string | DataTableCreateRowClassName<T>
  rowProps?: DataTableCreateRowProps<T>
  rowKey?: DataTableCreateRowKey<T>
  summary?: DataTableCreateSummary<T>
  bordered?: boolean
  bottomBordered?: boolean
  striped?: boolean
  scrollX?: string | number
  singleLine?: boolean
  singleColumn?: boolean
  remote?: boolean
  defaultExpandAll?: boolean
  stickyExpandedRows?: boolean
  virtualScroll?: boolean
  virtualScrollX?: boolean
  virtualScrollHeader?: boolean
  headerHeight?: number
  heightForRow?: DataTableHeightForRow<T>
  minRowHeight?: number
  tableLayout?: 'auto' | 'fixed'
  allowCheckingNotLoaded?: boolean
  cascade?: boolean
  childrenKey?: string
  indent?: number
  flexHeight?: boolean
  summaryPlacement?: 'top' | 'bottom'
  paginationBehaviorOnFilter?: 'first' | 'current'
  filterIconPopoverProps?: PopoverProps
  scrollbarProps?: ScrollbarProps
  renderCell?: (value: any, rowData: T, column: NvCrudFieldOption<T>) => VNodeChild
  renderExpandIcon?: (params: { expanded: boolean, rowData: T }) => VNodeChild
  spinProps?: SpinProps
  getCsvCell?: (value: any, rowData: T, column: NvCrudFieldOption<T>) => string
  getCsvHeader?: (column: NvCrudFieldOption<T>) => string
  onLoad?: (node: T) => Promise<void>

  id?: string
  targetStorage?: NvTargetStorage
  layout?: 'default' | 'simple' | Constructor

  searchForm?: NvSearchFormOption | boolean

  selection?: NvSelectionOption<T>
  serialNo?: NvSerialNoOption<T>
  expansion?: NvExpansionOption<T>

  multiSelectBar?: NvMultiSelectBarOption

  rowActions?: NvRowActionsOption | boolean

  actionbar?: NvActionbarOption | boolean
  toolbar?: NvToolbarOption | boolean

  formWrapper?: NvFormWrapper

  fields: Record<string, NvCrudFieldOption<T>>
}

export interface NvCrudInst {
  rowAdd: () => void
  rowView: (row: RowData) => void
  rowEdit: (row: RowData) => void
  rowDel: (row: RowData) => void
  closeForm: () => Promise<void>
  getFormRef: () => NvFormInst | undefined
  getSearchRef: () => NvSearchInst | undefined
}
